package org.cyz.tools.common.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.cyz.tools.common.bean.Version;
import org.cyz.tools.core.ContextManager;
import org.cyz.tools.core.assembly.Notify;
import org.cyz.tools.core.assembly.log.Log;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

/**
 * 更新工具  tools-platform-tools
 */
public class UpdateUtil {

    private static final String SERVER_URL = "http://chenyazhou.club:8090";
    //    private static final String SERVER_URL="http://127.0.0.1:8080";
    public static final String UPDATE_URL = SERVER_URL + "/update";
    public static final String FEED_BACK_URL = SERVER_URL + "/feedback";

    private static double xOffset = 0;
    private static double yOffset = 0;

    private static Task<Integer> task = createTask();

    public static Thread thread;
    public static Stage stage = new Stage();
    private static ProgressBar progressBar;
    private static Label info;
    private static Parent root = null;

    private static String message;
    private static long workDone = 0;
    private static long max = 0;


    public static void checkUpdate() {
        Platform.runLater(() -> {
            //读取本地版本
            String lVersion = PomUtil.getVersion();
            //获取远程版本
//            String rVersion = HttpUtil.get(getUrl(lVersion), CharsetUtil.CHARSET_UTF_8);
//            List<Version> versions = JSON.parseArray(rVersion, Version.class);
            Version rVersion = getRemoteVersion(lVersion);
            Log.info(UpdateUtil.class.getSimpleName(),"远程：" + rVersion.getVersion() + " 本地版本：" + lVersion);
            if (compress(lVersion, rVersion.getVersion())) {
                Log.info(UpdateUtil.class.getSimpleName(),"执行更新");
                ContextManager.stageManager.getStage("Main").setIconified(true);
                toUpdate(rVersion.getVersion(), rVersion.getUrl());
            } else {
                Log.info(UpdateUtil.class.getSimpleName(),"当前" + lVersion + "已是最新版本。");
            }
        });
    }

    public static Version getRemoteVersion(String lVersion) {
        //获取远程版本
//        String rVersion = HttpUtil.get(getUrl(lVersion), CharsetUtil.CHARSET_UTF_8);
        String rVersion = HttpUtil.get(getUrl(lVersion), 3000);
        List<Version> versions = JSON.parseArray(rVersion, Version.class);
        return versions.get(versions.size() - 1);
    }

    private static String getUrl(String version) {
        return UPDATE_URL + "?version=" + version;
    }

    /**
     * 返回true需要更新
     *
     * @param rV
     * @return
     */
    private static boolean compress(String lV, String rV) {
        lV = lV.replaceAll("\\.", "");
        //本地真实版本
        int _lv = Integer.parseInt(lV.replace("v", ""));
        if (StrUtil.isNotBlank(rV)) {
            String _rVersion = rV;
            _rVersion = _rVersion.replaceAll("\\.", "");
            int _rv = Integer.parseInt(_rVersion.replace("v", ""));
            if (_rv > _lv) {
                //需要更新
                return true;
            }
        }
        return false;
    }

    private static void toUpdate(String version, String url) {
//        int code = HttpUtil.createGet(url).execute().getStatus();
        int code = 200;
        switch (code) {
            case 404:
                Platform.runLater(() -> Notify.toast("检测到新版本[" + version + ",但是资源不存在了!😭"));
                break;
            case 200:
                Notify.notifyShowTime("更新提示", "检测到新版本[" + version + "],更新到新版本获得最佳体验！", 0, 10000);
                Platform.runLater(() -> {
                    showUpdateForms();
                });
                Platform.runLater(() -> {
                    max = getFileLength(url);
                });
                Platform.runLater(() -> {
                    bindProcess();
                });
                thread = new Thread(() -> download(url));
                thread.start();
                break;
            default:
                break;
        }
    }

    private static void showUpdateForms() {
        try {
            URL _url = UpdateUtil.class.getClassLoader().getResource("fxml/Update.fxml");
            root = FXMLLoader.load(_url);
            progressBar = (ProgressBar) root.lookup("#progressBar");
            info = (Label) root.lookup("#info");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //删除最大化最小化按钮（你可以用stage.setResizable(false)来做到这一点;您还可以使用stage.initStyle(StageStyle.UNDECORATED)删除）
        stage.initStyle(StageStyle.UNDECORATED);
        //拖动
        root.setOnMousePressed(event -> {
            xOffset = event.getSceneX();
            yOffset = event.getSceneY();
        });
        root.setOnMouseDragged(event -> {
            stage.setX(event.getScreenX() - xOffset);
            stage.setY(event.getScreenY() - yOffset);
        });
        stage.setTitle("应用更新");
        stage.setAlwaysOnTop(true);
        stage.getIcons().add(ImageUtil.getStartIcon("logo"));
        stage.setScene(new Scene(root, 385, 106));
        stage.show();
        System.out.println("workDone: " + workDone);
    }

    private static void bindProcess() {
        progressBar.progressProperty().bind(task.progressProperty());
        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();
    }


    private static void download(String url) {
        //带进度显示的文件下载
        HttpUtil.downloadFile(url, FileUtil.file(".redis-gui/"), new StreamProgress() {
            @Override
            public void start() {
                Log.info(UpdateUtil.class.getSimpleName(),"开始下载...");
                message = "开始下载...";
            }

            @Override
            public void progress(long progressSize) {
//                logger.info("已下载：{}", FileUtil.readableFileSize(progressSize));
                Platform.runLater(() -> {
                    info.setText(FileUtil.readableFileSize(max) + " / " + FileUtil.readableFileSize(workDone));
                });
                workDone = progressSize;
            }

            @Override
            public void finish() {
                Platform.runLater(()->{
                    Log.info(UpdateUtil.class.getSimpleName(),"下载完成！");
                    message = "下载完成!";
                    startSetup(url.split("/")[url.split("/").length - 1]);
                });
            }
        });
    }

    private static void startSetup(String path) {
        info.setText(message);
        info.setText("将启动安装进程...");
        try {
            CmdUtil.executeCmd(".redis-gui/" + path);
        } catch (IOException e) {
            Log.error(UpdateUtil.class.getSimpleName(),"启动失败!");
            info.setText("启动失败了!请手动执行【.redis-gui/" + path + "】");
        }
        UpdateUtil.stage.setIconified(true);
    }

    protected static Task<Integer> createTask() {
        return new Task<Integer>() {
            @Override
            protected Integer call() throws Exception {
                // 更新进度条及其文字
                while (workDone < max) {
                    updateProgress(workDone, max);
                    updateMessage(message);
                    Thread.sleep(1000);
                }
                // 关闭弹框
                UpdateUtil.stage.setIconified(true);
                return null;
            }
        };
    }


    private static long getFileLength(String url) {
        try {
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            // conn.setDoOutput(true);
            conn.setRequestMethod("HEAD");
            Map<String, List<String>> headerMap = conn.getHeaderFields();
            return Long.parseLong(headerMap.get("Content-Length").get(0));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


}
